home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / wnos / wn941101 / nntpcli.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-06  |  25.3 KB  |  1,113 lines

  1. /*
  2.  *
  3.  * NNTP Client - See RFC977
  4.  * Jeffrey R. Comstock. - NR0D - Bloomington, Minnesota USA
  5.  * Copyright 1990 Jeffrey R. Comstock, All Rights Reserved.
  6.  * Permission granted for non-commercial copying and use, provided
  7.  * this notice is retained.
  8.  *
  9.  * DB3FL 9107xx: heavily rewritten and bug fixing in file-handling
  10.  * DB3FL 920121: splitted into several files
  11.  * DB3FL 920131: included IHAVE command/offer to server
  12.  * DG1ZX 9210xx: minimizing overhead in ihave cmd and bug fixing
  13.  * DG1ZX 9303xx: included POST and XDHR command
  14.  * DG1ZX 930728: included nntp restrictions and history lifetime
  15.  *
  16.  */
  17.  
  18. #include <stdio.h>
  19. #include <dos.h>
  20. #include <time.h>
  21. #include <ctype.h>
  22. #include <dir.h>
  23. #include <io.h>
  24.  
  25. #include "global.h"
  26. #include "config.h"
  27. #include "nntp.h"
  28. #include "files.h"
  29. #include "domain.h"
  30. #include "socket.h"
  31. #include "cmdparse.h"
  32. #include "session.h"
  33. #ifdef LZW
  34. #include "lzw.h"
  35. #endif
  36.  
  37. char msgid[]         = "Message-Id: ";
  38. char subj[]         = "Subject: ";
  39. char ngrps[]         = "Newsgroups: ";
  40. char frm[]         = "From: ";
  41. char ndate[]        = "Date: ";
  42. static char reply_to[]    = "Reply-To: ";
  43. char pth[]        = "Path: ";
  44. static char quitcmd[]    = "QUIT\n";
  45.  
  46. static struct post Post;
  47. static struct Servers *Nntpserver = NULLSERVER;
  48.  
  49. static int16 NnIhave = 0;
  50.  
  51. #ifdef NNTPRESTRICT
  52. int restrict = 0;
  53. #endif
  54.  
  55. #ifdef NNTPLIFETIME
  56. int16 lifetime = 180;        /* default: 180 days */
  57. #endif
  58.  
  59.  
  60.  
  61. /* handles the response code of an incoming msg
  62.  * returncode: -1 error; 0 no code; value of response code on success */
  63. static int near
  64. getreply(struct nntpsv *cb)
  65. {
  66.   int response;
  67.   char *cp;
  68.  
  69.   while(recvline(cb->s,cb->buf,LineLen) != -1) {
  70.     /* skip informative messages and blank lines */
  71.     if(*cb->buf == '\0' || *cb->buf == '1')
  72.       continue;
  73.     if((cp = strchr(cb->buf,' ')) != NULLCHAR) {
  74.       *cp = '\0';
  75.       response = atoi(cb->buf);
  76.       *cp = ' ';
  77.     }
  78.     else {
  79.       response = 500;
  80.     }
  81.     return (response < 500) ? response : -1;
  82.   }
  83.   return -1;
  84. }
  85.  
  86. static char * near
  87. pollpos(char *line,char *name,FILE *f)
  88. {
  89.   long t;
  90.   char *cp;
  91.  
  92.   rewind(f);
  93.   for(t = 0L; fgets(line,LineLen,f) != NULLCHAR; t = ftell(f)) {
  94.     if((cp = strchr(line,' ')) == NULLCHAR)
  95.       continue;           /* something wrong with this line, skip it */
  96.     *cp = '\0';
  97.     if(strnicmp(line,name,strcspn(name," ")) == 0) {
  98.       fseek(f,t,SEEK_SET);
  99.       return cp+1;
  100.     }
  101.    }
  102.    return 0L;
  103. }
  104.  
  105. static void
  106. nntppoll(int unused, void *cb1, void *p)
  107. {
  108.     char    *cp, line[LINELEN], *firstpoll;
  109.     struct    sockaddr_in fsocket;
  110.     struct    nntpsv *cb;
  111.     struct    tm *ltm;
  112.     FILE    *f = NULLFILE, *f1 = NULLFILE, *pf;
  113.     int        err = 0, r, now, ret;
  114.     int32    lastday, SavePollTime;
  115.     struct    Servers *sp = (struct Servers *)cb1;
  116.  
  117.     if (!Filecheck)
  118.         if(check_system())
  119.             return;
  120.  
  121.     if(availmem() < Memthresh) {
  122.         start_timer(&sp->nntpt);
  123.         return;
  124.     }
  125.     /* check connection window (in local time !) */
  126.     ltm = localtime(&currtime);
  127.     now = ltm->tm_hour * 100 + ltm->tm_min;
  128.  
  129.     if (sp->lowtime < sp->hightime) {
  130.         /* doesn't cross midnight */
  131.         if (now < sp->lowtime || now >= sp->hightime) {
  132.             start_timer(&sp->nntpt);
  133.             return;
  134.         }
  135.     } else {
  136.         if (now < sp->lowtime && now >= sp->hightime) {
  137.             start_timer(&sp->nntpt);
  138.             return;
  139.         }
  140.     }
  141.  
  142.     /* save connection time to update pollfile (DG1ZX) */
  143.     SavePollTime = currtime;
  144.  
  145.     if((pf = open_file(Poll,"r+",0,1)) == NULLFILE ||
  146.       (cb = (struct nntpsv *)mxallocw(sizeof(struct nntpsv))) == NULLNNTPSV) {
  147.         start_timer(&sp->nntpt);
  148.         return;
  149.     }
  150.     stop_timer(&sp->nntpt);
  151.  
  152.     /* if no entry for host in poll-file exist, set date
  153.     to yesterday (DG1ZX) */
  154.  
  155.     if((cp = pollpos(line,sp->name,pf)) == NULLCHAR) {
  156.         lastday = currtime - 1*DAYS;
  157.         ltm = gmtime(&lastday);
  158.         sprintf(firstpoll,"%02d%02d%02d %02d%02d%02d",
  159.             ltm->tm_year,ltm->tm_mon + 1,ltm->tm_mday,
  160.             ltm->tm_hour,ltm->tm_min,ltm->tm_sec);
  161.         cb->newnews = strxdup(firstpoll);
  162.     } else {
  163.         rip2(cp);
  164.         cb->newnews = strxdup(cp);
  165.     }
  166.     fclose(pf);
  167.  
  168.     fsocket.sin_family = AF_INET;
  169.     fsocket.sin_addr.s_addr = cb->dest = sp->dest;
  170.     fsocket.sin_port = IPPORT_NNTP;
  171.  
  172.     if((cb->s = socket(AF_INET,SOCK_STREAM,0)) == -1)
  173.         goto quit;
  174.  
  175.     sockmode(cb->s,SOCK_ASCII);
  176.  
  177.     if(connect(cb->s,(char *)&fsocket,SOCKSIZE) == -1)
  178.         goto quit;
  179.  
  180.     log(cb->s,"NNTP Connect");
  181.  
  182.     if(getreply(cb) == -1)      /* throw away any hello msg */
  183.         goto quit;
  184.  
  185. #ifdef LZW
  186.     if (LzwActive)   {
  187.         usprintf(cb->s,"XLZW %d %d\n",Lzwbits,Lzwmode);
  188.         if((ret = getreply(cb)) == 235)   {       /* eat negative response */
  189.             lzwinit(cb->s,Lzwbits,Lzwmode);
  190.         }
  191.     }
  192. #endif
  193.  
  194.     usputs(cb->s,"SLAVE\n");
  195.     if(getreply(cb) != 202)
  196.         goto quit;
  197.     if((f = temp_file(0,1)) == NULLFILE)
  198.         goto quit;
  199.  
  200.     cb->slave = 1;
  201.  
  202.     usprintf(cb->s,"NEWNEWS %s %s GMT\n",sp->newsgroups,cb->newnews);
  203.  
  204.     if(getreply(cb) != 230)
  205.         goto quit1;
  206.     if(recv_file(f,cb->s) == -1)
  207.         goto quit1;
  208.     if((f1 = temp_file(cb->s,1)) == NULLFILE)
  209.         goto quit1;
  210.  
  211.     rewind(f);
  212.  
  213.     while(fgets(cb->buf,LineLen,f),!feof(f)) {
  214.         rip2(cb->buf);
  215.         if (strcmp(cb->buf,".") == 0)
  216.             break;
  217.         if (check_article(cb->buf) == 1)
  218.             continue;
  219.         usprintf(cb->s,"ARTICLE %s\n",cb->buf);
  220.         for (;;) {
  221.             if ((r = recvline(cb->s,cb->buf,LineLen)) == -1)
  222.                 break;
  223.             rip2(cb->buf);
  224.             if(!isdigit(cb->buf[0])) {
  225.                 r = -1;
  226.                 continue;
  227.             } else {
  228.                 r = atoi(cb->buf);
  229.                 break;
  230.             }
  231.         }
  232.         if(r == -1) {
  233.             fclose(f1);
  234.             goto quit1;
  235.         }
  236.         if (r == 220) {
  237.             if (recv_file(f1,cb->s) == -1) {
  238.                 fclose(f1);
  239.                 goto quit1;
  240.             }
  241.             rewind(f1);
  242.             while(fgets(cb->buf,LineLen,f1),!feof(f1)) {
  243.                 rip2(cb->buf);
  244.                 if (strnicmp(cb->buf,msgid,12) == 0) {
  245.                     cp = strchr(cb->buf,' ');
  246.                     cb->id = strxdup((*++cp < 32) ? "(none)" : cp);
  247.                     break;
  248.                 }
  249.             }
  250.             /* minimum header in article required !
  251.                Now check again, if same news exists in history
  252.                (DG1ZX) */
  253.             if (garbled(f1) == 0 && check_article(cb->id) == 0) {
  254.                 rewind(f1);
  255.                 xfer_article2(f1,cb);
  256.             }
  257.         }
  258.         fclose(f1);
  259.         if ((f1 = temp_file(cb->s,1)) == NULLFILE)
  260.             goto quit1;
  261.     }
  262.     fclose(f1);
  263.  
  264.  
  265.     /* IHAVE offer */
  266.  
  267.     if(NnIhave && (f1 = tmpfile()) != NULLFILE) {
  268.         sprintf(line,"%s %s",NnIhave == 2 ? "*" : sp->newsgroups,cb->newnews);
  269. #if (defined(NNTPRESTRICT) || defined(NNTPLIFETIME))
  270.         if(newnews(line,cb,f1,0) < 1) {
  271. #else
  272.         if(newnews(line,cb,f1) < 1) {
  273. #endif
  274.             fclose(f1);
  275.         }
  276.         else {
  277.             rewind(f1);
  278.             while(fgets(line,sizeof(line),f1),!feof(f1)) {
  279.                 /* check if MID exist at the other host (dg1zx) */
  280.                 if (check_ihave (f,line,cb,sp->name))
  281.                     continue;
  282.                 usprintf(cb->s,"IHAVE %s",line);
  283.                 if((ret = getreply(cb)) == -1) {
  284.                     err = 1;
  285.                     break;
  286.                 }
  287.                 if(ret != 335)
  288.                     continue;
  289.                 rip2(line);
  290.                 if(doarticle(line,cb,0,NULLCHAR) < 1) {
  291.                     usputs(cb->s,NEol);
  292.                     if((ret = getreply(cb)) == -1) {
  293.                         err = 1;
  294.                         break;
  295.                     }
  296.                     continue;
  297.                 }
  298.                 if((ret = getreply(cb)) != 235)
  299.                     continue;
  300.             }
  301.             fclose(f1);
  302.         }
  303.     }
  304.  
  305.     /*
  306.      * update pollfile
  307.      * Now write back the opening date and time.
  308.      * Time in poll and history files are always GMT (DG1ZX)
  309.      */
  310.  
  311.     if(!err && (pf = fopen(Poll,"r+")) != NULLFILE) {
  312.         pollpos(line,sp->name,pf);
  313.         ltm = gmtime(&SavePollTime);
  314.         fprintf(pf,"%s %02d%02d%02d %02d%02d%02d\n",
  315.             sp->name,
  316.             ltm->tm_year,ltm->tm_mon + 1,ltm->tm_mday,
  317.             ltm->tm_hour,ltm->tm_min,ltm->tm_sec);
  318.         fclose(pf);
  319.      }
  320.  
  321. quit1:
  322.     fclose(f);
  323. quit:
  324.     usprintf(cb->s,quitcmd);
  325.     if(getreply(cb) == -1) ;
  326.     close_s(cb->s);
  327.     xfree(cb->newnews);
  328.     xfree((char *)cb);
  329.     start_timer(&sp->nntpt);
  330. }
  331.  
  332. static void
  333. poll(void *p)
  334. {
  335.     newproc("NNTP Client", 2048, nntppoll, 0, p, NULL, 0);
  336. }
  337.  
  338. static char * near
  339. input_line(char *msg,struct session *sp)
  340. {
  341.     static char buf[LineLen];
  342.  
  343.     for (;;) {
  344.         usputs(sp->output,msg);
  345.         usflush(sp->output);
  346.         if(recvline(sp->input,buf,LineLen) == -1)
  347.             return NULLCHAR;
  348.         rip2(buf);
  349.         if(!check_blank(buf)) {
  350.             return buf;
  351.         }
  352.     }
  353. }
  354.  
  355.  
  356.  
  357. /* ---------------------- NNTP Client subcmds ----------------------- */
  358.  
  359. /* lists active newsgroups
  360.  * returncode: -1 if error; 0 success */
  361. static int
  362. donnactive(int argc,char *argv[],void *p)
  363. {
  364.     FILE *fp;
  365.     char line[80], *cp;
  366.  
  367.     if((fp = open_file(Active,READ_TEXT,0,1)) == NULLFILE)
  368.         return -1;
  369.  
  370.     tputs("last  first post newsgroup\n");
  371.  
  372.     while(fgets(line,sizeof(line),fp),!feof(fp)) {
  373.         if((cp = strchr(line,' ')) != NULLCHAR) {
  374.             *cp = '\0';
  375.             rip2(++cp);
  376.             tprintf("%s    %s\n",cp,line);
  377.         }
  378.     }
  379.     fclose(fp);
  380.     return 0;
  381. }
  382.  
  383. /* add nntp servers to list */
  384. static int
  385. donnadds(int argc,char *argv[],void *p)
  386. {
  387.     struct Servers *np;
  388.     int32 addr;
  389.  
  390.     if((addr = resolve(argv[1])) == 0) {
  391.         tprintf(Badhost,argv[1]);
  392.         return -1;
  393.     }
  394.     for(np = Nntpserver; np != NULLSERVER; np = np->next)
  395.         if(np->dest == addr)
  396.             break;
  397.     if (np == NULLSERVER) {
  398.         np = (struct Servers *)mxallocw(sizeof(struct Servers));
  399.         np->dest = addr;
  400.         np->name = strxdup(argv[1]);
  401.         np->next = Nntpserver;
  402.         Nntpserver = np;
  403.         np->newsgroups = NULLCHAR;
  404.         np->lowtime = np->hightime = -1;
  405.         np->nntpt.func = poll;        /* what to call on timeout */
  406.         np->nntpt.arg = (void *)np;
  407.     }
  408.     if (argc > 3) {
  409.         int i;
  410.         if (np->newsgroups == NULLCHAR) {
  411.             np->newsgroups = mxallocw(LineLen);
  412.             *np->newsgroups = '\0';
  413.         }
  414.         for (i = 3; i < argc; ++i) {
  415.             if (isdigit(*argv[i])) {
  416.                 char *cp, *cp1;
  417.  
  418.                 cp = argv[i];
  419.  
  420.                 if(((char *)((cp1 = strchr(cp,':')) != NULLCHAR)
  421.                   != strrchr(cp,':') && strchr(cp,'-'))) {
  422.                     /* there must be 2 different ':' and 1 '-' */
  423.                     *cp1 = 0;
  424.                     np->lowtime = atoi(cp) * 100;
  425.                     cp = ++cp1;
  426.                     while(*++cp != '-') ;
  427.                     *cp = '\0';
  428.                     np->lowtime += atoi(cp1);
  429.                     cp1 = ++cp;
  430.                     while(*++cp1 != ':') ;
  431.                     *cp1 = 0;
  432.                     np->hightime = atoi(cp) * 100 + atoi(++cp1);
  433.                 }
  434.             } else if ((strlen(np->newsgroups)+strlen(argv[i])+2) >= LineLen)
  435.                 tprintf("To many groups, '%s' ignored\n", argv[i]);
  436.             else {  /* it's a group, and it fits... add it to list */
  437.                 if (*np->newsgroups != '\0')
  438.                     strcat(np->newsgroups, ",");
  439.                 strcat(np->newsgroups, argv[i]);
  440.             }
  441.         }
  442.         if (*np->newsgroups == '\0') {    /* No groups specified? */
  443.             xfree(np->newsgroups);
  444.             np->newsgroups = NULLCHAR;
  445.         }
  446.     }
  447.     /* set timer duration */
  448.     set_timer(&np->nntpt,atol(argv[2]) * 1000L);
  449.     start_timer(&np->nntpt);        /* and fire it up */
  450.     return 0;
  451. }
  452.  
  453. /* drops nntp servers from list */
  454. static int
  455. donndrops(int argc,char *argv[],void *p)
  456. {
  457.     struct Servers *np, *npprev = NULLSERVER;
  458.     int32 addr;
  459.  
  460.     if((addr = resolve(argv[1])) == 0) {
  461.         tprintf(Badhost,argv[1]);
  462.     } else {
  463.         for(np = Nntpserver; np != NULLSERVER; npprev = np, np = np->next)
  464.             if(np->dest == addr) {
  465.                 stop_timer(&np->nntpt);
  466.                 xfree(np->name);
  467.                 if (np->newsgroups)
  468.                     xfree(np->newsgroups);
  469.                 if(npprev != NULLSERVER)
  470.                     npprev->next = np->next;
  471.                 else
  472.                     Nntpserver = np->next;
  473.                 xfree((char *)np);
  474.                 return 0;
  475.         }
  476.     }
  477.     return -1;
  478. }
  479.  
  480. /* copies a news from given newsgroup to the mailbox */
  481. static int
  482. donndump(int argc,char *argv[],void *p)
  483. {
  484.     FILE *t, *f, *o;
  485.     struct article *art;
  486.     char line[LineLen], newsname[10], *cp;
  487.     struct ffblk blk;
  488.  
  489.     if((art = (struct article *)mxallocw(sizeof(struct article))) == NULLARTICLE)
  490.         return -1;
  491.  
  492.     art->group = strxdup(argv[1]);
  493.  
  494.     if(get_path2(art) < 1)
  495.         goto error;
  496.  
  497.     rip2(art->path);
  498.     sprintf(line,"%s/*.*",art->path);
  499.  
  500.     if(findfirst(line,&blk,0)) {
  501.         tputs("No news in newsgroup\n");
  502.         goto error;
  503.     }
  504.  
  505.     sprintf(newsname,"%.8s",argv[2]);
  506.     sprintf(line,"%s/%s.txt",Mailspool,newsname);
  507.  
  508.     if ((o = open_file(line,"a+",0,1)) == NULLFILE)
  509.         goto error;
  510.     if(!(mlock(Mailspool,newsname))) {
  511.         tprintf("Newsgroup dump to %s\n",line);
  512.         for (;;) {
  513.             if((t = temp_file(0,1)) == NULLFILE) {
  514.                 fclose(o);
  515.                 goto error;
  516.             }
  517.             sprintf(line,"%s/%s",art->path,blk.ff_name);
  518.             /* Open the article */
  519.             if ((f = open_file(line,READ_TEXT,0,1)) == NULLFILE) {
  520.                 fclose(t);
  521.                 fclose(o);
  522.                 goto error;
  523.             }
  524.             pwait(NULL);
  525.             tputc('.');     /* One article/dot processed */
  526.             tflush();
  527.  
  528.             while(fgets(line,LineLen,f),!feof(f)) {
  529.                 fputs(line,t);
  530.                 if (!strnicmp(line,frm,6)) {
  531.                     cp = strchr(line,' ') + 1;
  532.                     fprintf(o,"From %s",cp);
  533.                 }
  534.             }
  535.             rewind(t);
  536.             while(fgets(line,LineLen,t),!feof(t))
  537.                 fputs(line,o);
  538.  
  539.             fputc('\n',o);
  540.             fclose(t);
  541.             fclose(f);
  542.             if (findnext(&blk))
  543.                 break;
  544.         }
  545.         rmlock(Mailspool,newsname);
  546.     } else
  547.         tputs("Mailfile is busy, try later");
  548.  
  549.     fclose(o);
  550.     tputs("\n");
  551.  
  552. error:
  553.     xfree(art->path);
  554.     xfree(art->group);
  555.     xfree(art);
  556.     return 0;
  557. }
  558.  
  559. static int
  560. donnfull(int argc,char *argv[],void *p)
  561. {
  562.     if(argc < 2 && Post.fullname != NULLCHAR)
  563.         tprintf("%s\n",Post.fullname);
  564.     else {
  565.         xfree(Post.fullname);
  566.         Post.fullname = strxdup(argv[1]);
  567.     }
  568.     return 0;
  569. }
  570.  
  571. static int
  572. donnhost(int argc,char *argv[],void *p)
  573. {
  574.     if(argc < 2 && Host != NULLCHAR)
  575.         tprintf("%s\n",Host);
  576.     else {
  577.         xfree(Host);
  578.         Host = strxdup(argv[1]);
  579.     }
  580.     return 0;
  581. }
  582.  
  583. static int
  584. donnihave(int argc,char *argv[],void *p)
  585. {
  586.     return setintrc(&NnIhave,"NNTP Ihave",argc,argv,0,2);
  587. }
  588.  
  589. static int
  590. donnkick(int argc,char *argv[],void *p)
  591. {
  592.     int32 addr;
  593.  
  594.     if((addr = resolve(argv[1])) == 0) {
  595.         tprintf(Badhost,argv[1]);
  596.     } else {
  597.         struct Servers *np;
  598.  
  599.         for(np = Nntpserver; np != NULLSERVER; np = np->next) {
  600.             if(np->dest == addr) {
  601.                 /* If the timer is running,
  602.                  * the timeout function can be called
  603.                  */
  604.                 if(run_timer(&np->nntpt) || dur_timer(&np->nntpt) == 0) {
  605.                     stop_timer(&np->nntpt);
  606.                     poll((void *)np);
  607.                 }
  608.                 return 0;
  609.             }
  610.         }
  611.         tputs("No such server\n");
  612.     }
  613.     return 0;
  614. }
  615.  
  616. #ifdef LZW
  617. /* sets LzwActive flag */
  618. static int
  619. donnlzw(int argc,char *argv[],void *p)
  620. {
  621.     return setbool(&LzwActive,"NNTP LZW",argc,argv);
  622. }
  623. #endif
  624.  
  625. /* list nntp servers */
  626. static int
  627. donnlists(int argc,char *argv[],void *p)
  628. {
  629.     struct Servers *np;
  630.     char tbuf[80];
  631.  
  632.     for(np = Nntpserver; np != NULLSERVER; np = np->next) {
  633.         if (np->lowtime != -1 && np->hightime != -1)
  634.             sprintf(tbuf, " -- %02d:%02d-%02d:%02d",
  635.                 np->lowtime/100, np->lowtime%100,
  636.                 np->hightime/100, np->hightime%100);
  637.         else
  638.             tbuf[0] = '\0';
  639.         tprintf("%-32s (%lu/%lu%s)\n   Groups: %s\n", np->name,
  640.             read_timer(&np->nntpt) /1000L,
  641.             dur_timer(&np->nntpt) /1000L,
  642.             tbuf,
  643.             np->newsgroups ? np->newsgroups : "");
  644.     }
  645.     return 0;
  646. }
  647.  
  648. static int
  649. donnmaxcli(int argc,char *argv[],void *p)
  650. {
  651.     extern unsigned short Nntpmaxcli;
  652.  
  653.     return setshort(&Nntpmaxcli,"NNTP maxcli",argc,argv);
  654. }
  655.  
  656. static int
  657. donnorgan(int argc,char *argv[],void *p)
  658. {
  659.     if(argc < 2 && Post.organ != NULLCHAR)
  660.         tprintf("%s\n",Post.organ);
  661.     else {
  662.         xfree(Post.organ);
  663.         Post.organ = strxdup(argv[1]);
  664.     }
  665.     return 0;
  666. }
  667.  
  668. /* manually entering new news
  669.  * returncode: -1 if error; 0 success */
  670. static int
  671. donnpost(int argc,char *argv[],void *p)
  672. {
  673.     struct session *sp;
  674.     struct nntpsv *mp;
  675.     char buf[LineLen], *cp;
  676.     long id;
  677.     FILE *f, *idf, *ufp;
  678.  
  679.     if (!Filecheck)
  680.         if(check_system())
  681.             return -1;
  682.  
  683.     if((sp = newsession("NNTP Post",MORE,0,1)) == NULLSESSION) {
  684.         tputs(Nosess);
  685.         return -1;
  686.     }
  687.     if((mp = (struct nntpsv *)mxallocw(sizeof(struct nntpsv))) == NULLNNTPSV)
  688.         return -1;
  689.  
  690.     for (;;) {
  691.         if ((f = temp_file(0,1)) == NULLFILE)
  692.             goto done;
  693.  
  694.         if (Post.user == NULLCHAR)
  695.             Post.user = strxdup(input_line("User name? ",sp));
  696.         fprintf(f,"%s%s\n",pth,Post.user);
  697.         fprintf(f,"%s%s@%s",frm,Post.user,Hostname);
  698.  
  699.         if (Post.fullname == NULLCHAR)
  700.             Post.fullname = strxdup(input_line("Fullname? ",sp));
  701.         fprintf(f," (%s)\n",Post.fullname);
  702.  
  703.         fprintf(f,"%s%s\n",ngrps,input_line("Newsgroup? ",sp));
  704.         fprintf(f,"%s%s\n",subj,input_line("Subject? ",sp));
  705.  
  706.         id = get_msgid();
  707.         fprintf(f,"%s<%ld@%s>\n",msgid,id,Hostname);
  708.         fprintf(f,"Date: %s",ptime(&currtime));
  709.         fprintf(f,"Sender: NNTP@%s\n",Hostname);
  710.  
  711.         if (Post.reply != NULLCHAR)
  712.             fprintf(f,"%s%s\n",reply_to,Post.reply);
  713.  
  714.         if (Post.organ != NULLCHAR)
  715.             fprintf(f,"Organization: %s\n",Post.organ);
  716.  
  717.         fputc('\n',f);
  718.         tputs("Enter message - end with .\n");
  719.  
  720.         for (;;) {
  721.             if(recvline(sp->input,buf,LineLen) == -1)
  722.                 break;
  723.             if(strcmp(buf,".u\n") == 0
  724.               || strcmp(buf,".r\n") == 0) {
  725.                 tputs("Filename? ");
  726.                 recvline(sp->input,buf,LineLen);
  727.                 rip2(buf);
  728.                 if(*buf != '\0'
  729.                   && (ufp = open_file(buf,READ_TEXT,0,1)) != NULLFILE) {
  730.                     while(fgets(buf,LineLen,ufp),!feof(ufp))
  731.                         fputs(buf,f);
  732.                     fclose(ufp);
  733.                 }
  734.                 tputs("(continue)\n");
  735.             }
  736.             if(strcmp(buf,".\n") == 0
  737.               || strcmpi(buf,"***END\n") == 0
  738.               || strcmpi(buf,"/EX\n") == 0)
  739.                 break;
  740.             fputs(buf,f);
  741.         }
  742.         if (Post.sig != NULLCHAR) {
  743.             if ((idf = fopen(Post.sig,READ_TEXT)) != NULLFILE ) {
  744.                 while(fgets(buf,LineLen,idf),!feof(idf))
  745.                     fputs(buf,f);
  746.                 fclose(idf);
  747.                 tputs("(Sig-file appended)\n");
  748.             }
  749.         }
  750.         tputc('\n');
  751.  
  752. loop:   cp = input_line("[Send, Abort, Exit, List] ",sp);
  753.         switch(tolower(*cp)) {
  754.         case 's':
  755.             rewind(f);
  756.             sprintf(mp->buf,"<%ld@%s>",id,Hostname);
  757.             mp->id = strxdup(mp->buf);
  758.             xfer_article2(f,mp);
  759.             break;
  760.         case 'l':
  761.             rewind(f);
  762.             while(fgets(buf,LineLen,f),!feof(f))
  763.                 tputs(buf);
  764.             rewind(f);
  765.             goto loop;
  766.         case 'e':
  767.             fclose(f);
  768.             goto done;
  769.         case 'a':
  770.             break;
  771.         default:
  772.             goto loop;
  773.         }
  774.         fclose(f);
  775.         cp = input_line("Post another? (y/n) ",sp);
  776.         if(tolower(*cp) == 'n')
  777.             goto done;
  778.     }
  779.  
  780. done:
  781.     keywait(NULLCHAR,1);
  782.     xfree((char *) mp);
  783.     freesession(sp);
  784.     return 0;
  785. }
  786.  
  787. static int
  788. donnquiet(int argc,char *argv[],void *p)
  789. {
  790.     return setintrc(&Nntpquiet,"NNTP quiet",argc,argv,0,3);
  791. }
  792.  
  793. static int
  794. donnread(int argc,char *argv[],void *p)
  795. {
  796.     FILE *f;
  797.     struct session *sp;
  798.     struct article *art;
  799.     char cp[LINELEN], buf[81];
  800.     int number, row, flag = argc;
  801.  
  802.     if((art = (struct article *)mxallocw(sizeof(struct article))) == NULLARTICLE)
  803.         return -1;
  804.  
  805.     art->group = strxdup(argv[1]);
  806.     if(get_path2(art) == 1) {
  807.         if(argc > 2) {
  808.             number = atoi(argv[2]);
  809.         } else
  810.             number = 1;
  811.  
  812.         sprintf(cp,"%s/news.rc",art->path);
  813.         if(flag < 3 && (f = fopen(cp,READ_TEXT)) != NULLFILE) {
  814.             if((fgets(buf,sizeof(buf),f)) != 0) {
  815.                 number = atoi(buf);
  816.                 number++;
  817.             }
  818.             fclose(f);
  819.         }
  820.         if((sp = newsession("NNTP read",MORE,0,1)) != NULLSESSION) {
  821.             for(;;) {
  822.                 if(number < 1)
  823.                     number = 1;
  824.                 sp->ttystate.echo = sp->ttystate.edit = 0;
  825.                 row = Nrows - 4;
  826.                 sprintf(cp,"%s/%d",art->path,number);
  827.  
  828.                 if((f = fopen(cp,READ_TEXT)) != NULLFILE) {
  829.                     tprintf("Msg #%d\n",number);
  830.                     while(fgets(buf,sizeof(buf),f),!feof(f)) {
  831.                         tputs(buf);
  832.                         if(--row == 0){
  833.                             row = keywait("--More--",0);
  834.                             switch(row){
  835.                             case -1:
  836.                             case 'q':
  837.                                 fclose(f);
  838.                                 goto done;
  839.                             case '\n':
  840.                             case '\r':
  841.                                 row = 2;
  842.                                 break;
  843.                             default:
  844.                                 row = Nrows - 3;
  845.                             }
  846.                         }
  847.                     }
  848.                     fclose(f);
  849.                 } else {
  850.                     number--;
  851.                     tputs("No more news");
  852.                 }
  853. done:
  854.                 row = keywait("\nRead next/previous? (n/p/q)",0);
  855.                 switch(row) {
  856.                     case -1:
  857.                     case 'q':
  858.                         goto done2;
  859.                     case 'p':
  860.                         flag = 3;
  861.                         if(--number < 1)
  862.                             goto done2;
  863.                         continue;
  864.                     default:
  865.                         number++;
  866.                         continue;
  867.                 }
  868.             }
  869. done2:
  870.             if(flag < 3) {
  871.                 sprintf(cp,"%s/news.rc",art->path);
  872.                 if((f = fopen(cp,WRITE_TEXT)) != NULLFILE) {
  873.                     sprintf(cp,"%d\n",number);
  874.                     fputs(cp,f);
  875.                     fclose(f);
  876.                 }
  877.             }
  878.             keywait(NULLCHAR,1);
  879.             freesession(sp);
  880.         }
  881.     } else {
  882.         tprintf("No such newsgroup %s\n",art->group);
  883.     }
  884.     xfree(art->path);
  885.     xfree(art->group);
  886.     xfree(art);
  887.     return 0;
  888. }
  889.  
  890. static int
  891. donnreply(int argc,char *argv[],void *p)
  892. {
  893.     if(argc < 2 && Post.reply != NULLCHAR)
  894.         tprintf("%s\n",Post.reply);
  895.     else {
  896.         xfree(Post.reply);
  897.         Post.reply = strxdup(argv[1]);
  898.     }
  899.     return 0;
  900. }
  901.  
  902. static int
  903. donnsig(int argc,char *argv[],void *p)
  904. {
  905.     char buf[80];
  906.  
  907.     if(argc < 2 && Post.sig != NULLCHAR)
  908.         tprintf("%s\n",Post.sig);
  909.     else if(argc > 1) {
  910.         sprintf(buf,"%s/%s",Signature,argv[1]);
  911.         if(access(buf,0) == 0) {
  912.             if(Post.sig != NULLCHAR)
  913.                 xfree(Post.sig);
  914.         Post.sig = strxdup(buf);
  915.         } else {
  916.             tputs("No such signature file\n");
  917.             return -1;
  918.         }
  919.     }
  920.     return 0;
  921. }
  922.  
  923. static int
  924. donnuser(int argc,char *argv[],void *p)
  925. {
  926.     if(argc < 2 && Post.user != NULLCHAR)
  927.         tprintf("%s\n",Post.user);
  928.     else {
  929.         xfree(Post.user);
  930.         Post.user = strxdup(argv[1]);
  931.     }
  932.     return 0;
  933. }
  934.  
  935.  
  936. /****************************************************************/
  937. /*                                 */
  938. /*  This command will add a new newsgroup to the filesystem.     */
  939. /*                                 */
  940. /*  Syntax: nntp create <newsgroup>                */
  941. /*  Example: nntp create ampr.news.nrn.sources             */
  942. /*                                 */
  943. /****************************************************************/
  944.  
  945. static int
  946. donncreate(int argc, char *argv[], void *p)
  947. {
  948.     FILE *f;
  949.     char line[LineLen];
  950.     int     update_cntrl = 0;
  951.  
  952.     if ((f = open_file(Pointer,READ_TEXT,0,1)) == NULLFILE)
  953.         return -1;
  954.  
  955.     for (;;) {
  956.         if (fgets(line,LineLen,f) == NULL) {
  957.             /* update pointerfile */
  958.             update_cntrl = 1;
  959.             break;
  960.         }
  961.         if (strcspn(line," ") != strlen(argv[1]))
  962.             continue;
  963.         if (strnicmp(argv[1],line,strlen(argv[1])) == 0)
  964.             /* newsgroup in pointerfile exists */
  965.             break;
  966.     }
  967.     fclose(f);
  968.     /* creating path to this newsgroup */
  969.     if (make_path(argv[1],update_cntrl))
  970.         return -1;
  971.  
  972.     if ( (f=fopen(Active,APPEND_TEXT))==NULLFILE )
  973.         return -1;
  974.  
  975.     for (;;) {
  976.         if (fgets(line,LineLen,f) == NULL) {
  977.             /* update active file */
  978.             fprintf(f,"%s 00000 00001 y\n",argv[1]);
  979.             break;
  980.         }
  981.         if (strcspn(line," ") != strlen(argv[1]))
  982.             continue;
  983.         if (strnicmp(argv[1],line,strlen(argv[1])) == 0)
  984.             /* newsgroup in active file exists */
  985.             break;
  986.     }
  987.     fclose(f);
  988.     return 0;
  989. }
  990.  
  991. /********************************************************************/
  992. /*                                     */
  993. /*  This command will control, how incoming articles are processed. */
  994. /*  If fullauto flag is set, the nntp control files are updated to  */
  995. /*  include the new group and the subdirectories are automaticly    */
  996. /*  generated. Otherwise, all news that are not in the active file  */
  997. /*  will go to \spool\news\junk.                    */
  998. /*                                      */
  999. /*  Syntax: nntp config <yes|no>                    */
  1000. /*  Default: nntp config yes                        */
  1001. /*                                     */
  1002. /********************************************************************/
  1003.  
  1004. static int
  1005. donnconfig(int argc,char *argv[],void *p)
  1006. {
  1007.     return setbool(&fullauto,"NNTP AutoConfig",argc,argv);
  1008. }
  1009.  
  1010.  
  1011.  
  1012. #ifdef POST_ENBL
  1013. /*************************************************************/
  1014. /*                                 */
  1015. /*     Set POST-Command enable/disable                 */
  1016. /*                                  */
  1017. /*     Syntax: nntp post <yes|no>                 */
  1018. /*     Default: nntp post yes                          */
  1019. /*                                  */
  1020. /*************************************************************/
  1021.  
  1022. static int
  1023. dopostok(int argc,char *argv[],void *p)
  1024. {
  1025.     return setbool(&postingok,"NNTP Posting",argc,argv);
  1026. }
  1027. #endif
  1028.  
  1029.  
  1030. #ifdef NNTPLIFETIME
  1031. /*************************************************************/
  1032. /*                                  */
  1033. /*  Set History Lifetime (unit: days)                      */
  1034. /*                                  */
  1035. /*  NEWNEWS-Polls with date/time older than lifetime         */
  1036. /*  will not accepted. Incoming news are redirected to \JUNK */
  1037. /*                                  */
  1038. /*  Syntax: nntp lifetime <value>                 */
  1039. /*  Default: nntp lifetime 180                     */
  1040. /*                                  */
  1041. /*************************************************************/
  1042.  
  1043. static int
  1044. dolifetime(int argc,char *argv[],void *p)
  1045. {
  1046.     return setintrc(&lifetime,"NNTP Lifetime",argc,argv,1,3650);
  1047. }
  1048.  
  1049. #endif
  1050.  
  1051.  
  1052. #ifdef NNTPRESTRICT
  1053. /*************************************************************/
  1054. /*                                  */
  1055. /*  Enable/Disable NNTP restriction in handling newnews      */
  1056. /*  command without top level group specification         */
  1057. /*                                  */
  1058. /*  Syntax: nntp restrict <yes|no>                 */
  1059. /*  Default: nntp restrict no                     */
  1060. /*                                  */
  1061. /*************************************************************/
  1062.  
  1063. static int
  1064. dorestrict(int argc,char *argv[],void *p)
  1065. {
  1066.     return setbool(&restrict,"NNTP Restriction",argc,argv);
  1067. }
  1068. #endif
  1069.  
  1070.  
  1071. /* cmd parser */
  1072. int
  1073. donntp(int argc,char *argv[],void *p)
  1074. {
  1075.     struct cmds Nntp[] = {
  1076.         "active",    donnactive,    0,    0,    NULLCHAR,
  1077.         "add",        donnadds,    0,    3,    "nntp add <hostid> <interval> [hh:mm-hh:mm] <groups>",
  1078.         "config",    donnconfig,    0,    0,    NULLCHAR,
  1079.         "create",    donncreate,    0,    2,    "nntp create <newsgroup>",
  1080.         "drop",        donndrops,    0,    2,    "nntp drop <newsserver>",
  1081.         "dump",     donndump,     0,    3,    "nntp dump <newsgroup> <mailfile>",
  1082.         "fullname",    donnfull,    0,    0,    NULLCHAR,
  1083.         "hostname",    donnhost,    0,    0,    NULLCHAR,
  1084.         "ihave",    donnihave,    0,    0,    NULLCHAR,
  1085.         "kick",     donnkick,     0,    2,    "nntp kick <newsserver>",
  1086. #ifdef NNTPLIFETIME
  1087.         "lifetime",     dolifetime,     0,    0,    NULLCHAR,
  1088. #endif
  1089.         "list",        donnlists,    0,    0,    NULLCHAR,
  1090. #ifdef LZW
  1091.         "lzw",        donnlzw,    0,    0,    NULLCHAR,
  1092. #endif
  1093.         "maxclient",    donnmaxcli,    0,    0,    NULLCHAR,
  1094.         "organ",    donnorgan,    0,    0,    NULLCHAR,
  1095.         "post",     donnpost,    2048,    0,    NULLCHAR,
  1096. #ifdef POST_ENBL
  1097.         "postok",    dopostok,    0,    0,    NULLCHAR,
  1098. #endif
  1099.         "quiet",    donnquiet,    0,    0,    NULLCHAR,
  1100.         "read",        donnread,    1024,    2,    "nntp read <newsgroup> [number]",
  1101.         "reply",    donnreply,    0,    0,    NULLCHAR,
  1102. #ifdef NNTPRESTRICT
  1103.         "restrict",     dorestrict,    0,    0,      NULLCHAR,
  1104. #endif
  1105.         "signature",    donnsig,    0,    0,    NULLCHAR,
  1106.         "user",        donnuser,    0,    0,    NULLCHAR,
  1107.         NULLCHAR,
  1108.     };
  1109.  
  1110.     return (subcmd(Nntp,argc,argv,p));
  1111. }
  1112.  
  1113.